using System.IO;
using System.Runtime.Serialization;
using lucere.analysis.index;
using lucere.analysis.query;
using lucere.analysis.score;
using lucere.service.search.collect;

namespace lucere.service.search
{
	///<summary>
	/// Expert: Calculate query weights and build query scorers.
	/// <p>
	/// The purpose of <see cref="IWeight"></see> is to ensure searching does not
	/// modify a <see cref="IQuery"></see>, so that a <see cref="IQuery"></see> instance can be reused. <br/>
	/// <see cref="ISearcher"></see> dependent state of the query should reside in the
	/// <see cref="IWeight"></see>. <br/>
	/// <see cref="IIndexReader"></see> dependent state should reside in the <see cref="IScorer"></see>.
	/// </p>
	/// A <code>Weight</code> is used in the following way:
	/// <ol>
	/// <li>A <code>Weight</code> is constructed by a top-level query, given a
	/// <code>Searcher</code> (<see cref="IQuery.CreateWeight(ISearcher)"></see>).
	/// </li>
	/// <li>The <see cref="SumOfSquaredWeights()"></see> method is called on the
	/// <code>Weight</code> to compute the query normalization factor
	/// <see cref="ISimilarity.QueryNorm(float)"></see> of the query clauses contained in the
	/// query.
	/// </li>
	/// <li>The query normalization factor is passed to <see cref="Normalize(float)"></see>. At
	/// this point the weighting is complete.
	/// </li>
	/// <li>A <code>Scorer</code> is constructed by <see cref="Scorer(IIndexReader,bool,bool)"></see>.
	/// </li>
	/// </ol>
	///</summary>
	public interface IWeight : ISerializable
	{
		///<summary>
		/// An explanation of the score computation for the named document.
		///</summary>
		/// <param name="doc">doc</param>
		/// <param name="reader">sub-reader containing the give doc</param>
		/// <returns>an Explanation for the score</returns>
		///<exception cref="IOException"></exception>
		IExplanation Explain(IIndexReader reader, int doc);

		///<summary>
		/// The query that this concerns. 
		/// </summary>
		IQuery Query { get; }

		///<summary>
		/// The weight for this query. 
		/// </summary>
		float Value { get; }

		///<summary>
		/// Assigns the query normalization factor to this. 
		/// </summary>
		void Normalize(float norm);

		///<summary>
		/// Returns a <see cref="IScorer"></see> which scores documents in/out-of order according
		/// to <code>scoreDocsInOrder</code>.
		/// <b>NOTE:</b> even if <code>ScoreDocsInOrder</code> is false, it is
		/// recommended to check whether the returned <code>Scorer</code> indeed scores
		/// documents out of order (i.e., call <see cref="ScoresDocsOutOfOrder"></see>), as
		/// some <code>Scorer</code> implementations will always return documents
		/// in-order.<br/>
		/// <b>NOTE:</b> null can be returned if no documents will be scored by this
		/// query.
		/// <param name="reader">the <see cref="IIndexReader"></see> for which to return the <see cref="IScorer"></see>.</param>
		/// <param name="scoreDocsInOrder">
		///          specifies whether in-order scoring of documents is required. Note
		///          that if set to false (i.e., out-of-order scoring is required),
		///          this method can return whatever scoring mode it supports, as every
		///          in-order scorer is also an out-of-order one. However, an
		///          out-of-order scorer may not support <see cref="IScorer.NextDoc()"></see>
		///          and/or <see cref="IScorer.Advance(int)"></see>, therefore it is recommended to
		///          request an in-order scorer if use of these methods is required.
		/// </param>
		/// <param name="topScorer">
		///          if true, <see cref="IScorer.Score(ICollector)"></see> will be called; if false,
		///          <see cref="IScorer.NextDoc()"></see> and/or <see cref="IScorer.Advance(int)"></see> will
		///          be called.
		/// </param>
		/// <returns>a <see cref="IScorer"></see> which scores documents in/out-of order.</returns>
		/// <exception cref="IOException"></exception>
		///</summary>
		IScorer Scorer(IIndexReader reader, bool scoreDocsInOrder, bool topScorer);

		/// The sum of squared weights of contained query clauses. ////
		float SumOfSquaredWeights();

		///<summary>
		/// Returns true if this implementation scores docs only out of order. This
		/// method is used in conjunction with <see cref="ICollector"></see>'s
		/// <see cref="ICollector.AcceptsDocsOutOfOrder()"></see> and
		/// <see cref="Scorer(IIndexReader, bool, bool)"></see> to
		/// create a matching <see cref="IScorer"></see> instance for a given <see cref="ICollector"></see>, or
		/// vice versa.
		/// <b>NOTE:</b> the default implementation returns <code>false</code>, i.e.
		/// the <code>Scorer</code> scores documents in-order.
		///</summary>
		bool ScoresDocsOutOfOrder { get; }
	}
}